package net.app.zoneland.platform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.app.zoneland.common.core.vo.Result;
import net.app.zoneland.constant.AdminConstant;
import net.app.zoneland.domain.SysMenu;
import net.app.zoneland.platform.mapper.SysMenuMapper;
import net.app.zoneland.platform.service.ISysMenuService;
import net.app.zoneland.vo.MenuTreeVo;
import net.app.zoneland.vo.MenuVO;
import net.app.zoneland.vo.RouterVO;
import net.app.zoneland.vo.TreeSelectVO;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * @Description 菜单实现类
 * @Author cjb
 * @CreateTime 2020/12/26 12:57
 * @Version: 1.0
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    @Override
    public List<MenuVO> listForTableData(LambdaQueryWrapper<SysMenu> baseQuery) {
        baseQuery.orderByDesc(SysMenu::getSort);
        // 查询所有菜单
        List<SysMenu> menuList = this.baseMapper.selectList(baseQuery);
        List<MenuVO> list = recursionForTableData(AdminConstant.ROOT_MENU_ID, menuList);
        return list;
    }

    @Override
    public List<TreeSelectVO> listForTreeSelect(LambdaQueryWrapper<SysMenu> baseQuery) {
        List<SysMenu> menuList = this.list(baseQuery);
        List<TreeSelectVO> list = recursionForTreeSelect(AdminConstant.ROOT_MENU_ID, menuList);
        return list;
    }

    @Override
    public List<TreeSelectVO> listForTreeSelectByRole(SysMenu baseQuery) {
        List<SysMenu> menuList = this.baseMapper.listByRoleId(baseQuery);
        List<TreeSelectVO> list = recursionForTreeSelect(AdminConstant.ROOT_MENU_ID, menuList);
        return list;
    }

    @Override
    public List listForRouter() {
        List<SysMenu> menuList = this.baseMapper.listForRouter();
        List<RouterVO> list = recursionForRoutes(AdminConstant.ROOT_MENU_ID, menuList);
        return list;
    }

    @Override
    public List<MenuVO> queryMenus(String username) {
        return this.baseMapper.queryMenuByUsername(username);
    }

    @Override
    public Result saveOrUp(MenuTreeVo menu) {
            SysMenu sysMenu=new SysMenu();
            Integer parentId = menu.getParentId();
            if(parentId==null){
                parentId=0;
            }
            Integer isMenu = menu.getIsMenu();
            // 校验类型
            if(parentId==0){
                // 当父类为目录时，菜单类型不能为目录，菜单类型也不能为按钮
                if(isMenu==null || isMenu!=0 || isMenu==3){
                    return Result.error("类型选择有误!");
                }
            }else{
                LambdaQueryWrapper<SysMenu> baseQuery = new LambdaQueryWrapper<SysMenu>()
                        .eq(SysMenu::getId,parentId);
                SysMenu parentMenu = this.baseMapper.selectOne(baseQuery);
                if(parentMenu!=null){
                    Integer parentType = parentMenu.getType();
                    // 如果父类是菜单类型，则不能创建菜单
                    if(parentType==1 && isMenu==1){
                        return Result.error("菜单目录不能创建菜单");
                    }
                    if(parentType==2 && isMenu==2){
                        return Result.error("按钮类型下不能创建子集");
                    }
                }else {
                    return Result.error("您选择的上级不存在");
                }
            }

            String menuName = menu.getMenuName();
            sysMenu.setName(menuName);
            sysMenu.setParentId(parentId);
            sysMenu.setSort(menu.getSort());
            sysMenu.setIcon(menu.getMenuIcon());
            sysMenu.setType(menu.getIsMenu());
            sysMenu.setPerms(menu.getPerms());
            sysMenu.setPath(menu.getMenuUrl());
            // 新增
            if(menu.getId()==null || "".equals(menu.getId())){
                sysMenu.setVisible(0);
                sysMenu.setStatus(0);
                sysMenu.setGmtCreate(new Date());
                this.baseMapper.insert(sysMenu);
            }else{
                sysMenu.setId(menu.getId());
                sysMenu.setGmtModified(new Date());
            // 更新
                this.baseMapper.updateById(sysMenu);
            }
            return Result.success();

    }

    @Override
    public List<SysMenu> queryMenus(Integer id) {
        LambdaQueryWrapper<SysMenu> baseQuery = new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getParentId,id);
        List<SysMenu> sysMenus = this.baseMapper.selectList(baseQuery);
        return sysMenus;
    }

    @Override
    public IPage<SysMenu> list(Page<SysMenu> page, SysMenu menu) {
        return this.baseMapper.list(page,menu);
    }

    @Override
    public List<MenuTreeVo> getMenus(SysMenu menu) {
        List<MenuTreeVo> menus = this.baseMapper.getMenus(menu);
        if(menus!=null && !menus.isEmpty()){
            menus.forEach(m ->{
                if(m.getParentId()==0){ m.setParentId(-1);}
            });
        }
        return menus;
    }

    @Override
    public void deleteByIds(Integer id) {
        LambdaQueryWrapper<SysMenu> baseQuery=new LambdaQueryWrapper<SysMenu>();
        List<SysMenu> menuList = this.baseMapper.selectList(baseQuery);
        List<MenuVO> list = recursionForTableData(id, menuList);
        List<Integer> ids=new ArrayList<>();
        ids.add(id);
        if(list!=null && !list.isEmpty()){
            ids = addIds(ids, list);
        }
        this.baseMapper.deleteByBatch(ids);
    }

    private List<Integer> addIds(List<Integer> ids, List<MenuVO> menus){
        for (MenuVO men:menus){
            ids.add(men.getId());
            List<MenuVO> children = men.getChildren();
            if(children!=null && !children.isEmpty()){
                addIds(ids,children);
            }
        }
        return ids;
    }

    /**
     * 递归生成路由
     * @param parentId
     * @param menuList
     * @return
     */
    private List<RouterVO> recursionForRoutes(int parentId, List<SysMenu> menuList) {
        List<RouterVO> list = new ArrayList<>();
        Optional.ofNullable(menuList).orElse(new ArrayList<>())
                .stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .forEach(menu -> {
                    RouterVO routerVO = new RouterVO();
                    routerVO.setName(menu.getName());
                    if (parentId == AdminConstant.ROOT_MENU_ID) {
                        routerVO.setAlwaysShow(Boolean.TRUE);
                        routerVO.setPath("/" + menu.getPath());
                    } else {
                        routerVO.setPath(menu.getPath());
                    }
                    routerVO.setRedirect(menu.getRedirect());
                    routerVO.setComponent(
                            StrUtil.isNotBlank(menu.getComponent()) ?
                                    menu.getComponent() :
                                    "Layout");

                    routerVO.setMeta(routerVO.new Meta(
                            menu.getName(),
                            menu.getIcon(),
                            menu.getRoles()
                    ));
                    List<RouterVO> children = recursionForRoutes(menu.getId(), menuList);
                    routerVO.setChildren(children);
                    list.add(routerVO);
                });
        return list;
    }

    /**
     * 递归生成菜单表格数据
     * @param parentId
     * @param menuList
     * @return
     */
    public static List<MenuVO> recursionForTableData(int parentId, List<SysMenu> menuList) {
        List<MenuVO> list = new ArrayList<>();
        Optional.ofNullable(menuList).orElse(new ArrayList<>())
                .stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .forEach(menu -> {
                    MenuVO menuVO = new MenuVO();
                    BeanUtil.copyProperties(menu, menuVO);
                    List<MenuVO> children = recursionForTableData(menu.getId(), menuList);
                    menuVO.setChildren(children);
                    list.add(menuVO);
                });
        return list;
    }

    /**
     * 递归生成部门树形下拉数据
     *
     * @param parentId
     * @param menuList
     * @return
     */
    public static List<TreeSelectVO> recursionForTreeSelect(int parentId, List<SysMenu> menuList) {
        List<TreeSelectVO> list = new ArrayList<>();
        Optional.ofNullable(menuList).orElse(new ArrayList<>())
                .stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .forEach(menu -> {
                    TreeSelectVO treeSelectVO = new TreeSelectVO();
                    treeSelectVO.setId(menu.getId());
                    treeSelectVO.setLabel(menu.getName());
                    treeSelectVO.setPath(menu.getPath());
                    treeSelectVO.setIcon(menu.getIcon());
                    treeSelectVO.setType(menu.getType());
                    treeSelectVO.setParentId(menu.getParentId());
                    List<TreeSelectVO> children = recursionForTreeSelect(menu.getId(), menuList);
                    treeSelectVO.setChildren(children);
                    list.add(treeSelectVO);
                });
        return list;
    }
}
